package cn.com.nes.site.modules.opportuntiy;

import cn.com.nes.common.util.CopyUtils;
import cn.com.nes.common.util.OssUtil;
import cn.com.nes.common.util.id.IdUtils;
import cn.com.nes.mybatis.agent.crm.entity.Opportunity;
import cn.com.nes.mybatis.agent.crm.entity.OpportunityDeviceModel;
import cn.com.nes.mybatis.agent.project.entity.ProjectCustomerRelationship;
import cn.com.nes.mybatis.agent.project.entity.TProject;
import cn.com.nes.site.entity.em.DeleteEnum;
import cn.com.nes.site.entity.em.crm.clue.ClueStageEnum;
import cn.com.nes.site.entity.em.crm.customer.CustomerNatureEnum;
import cn.com.nes.site.entity.em.crm.opportunity.*;
import cn.com.nes.site.entity.em.project.ProjectRelationTypeEnum;
import cn.com.nes.site.entity.vo.crm.SaveUpdateClueVo;
import cn.com.nes.site.service.crm.clue.CrmClueService;
import cn.com.nes.site.service.crm.customer.bo.GetLogClaimListBo;
import cn.com.nes.site.service.crm.log.LogClaimService;
import cn.com.nes.site.service.crm.log.LogOperateService;
import cn.com.nes.site.service.crm.log.dto.GetLogClaimListDto;
import cn.com.nes.site.service.crm.opportunity.*;
import cn.com.nes.site.service.crm.opportunity.bo.*;
import cn.com.nes.site.service.crm.opportunity.dto.*;
import cn.com.nes.site.service.project.ProjectCustomerRelationshipService;
import cn.com.nes.site.service.project.TProjectService;
import cn.com.nes.site.service.system.region.XzqhService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商务项目公共业务处理
 */
@Slf4j
@Service
public class CommonOpportunityHandle implements OpportunityHandle {

    @Resource
    private CrmClueService crmClueService;

    @Resource
    protected CrmOpportunityService crmOpportunityService;

    @Resource
    private OpportunityStaffService opportunityStaffService;

    @Resource
    private OpportunityFileService opportunityFileService;

    @Resource
    private LogOperateService logOperateService;

    @Resource
    private LogClaimService logClaimService;

    @Resource
    private OpportunityQuoteService opportunityQuoteService;

    @Resource
    private OpportunityBimService opportunityBimService;

    @Resource
    private BimDesignService bimDesignService;

    @Resource
    protected OpportunityAreaCodeService opportunityAreaCodeService;

    @Resource
    protected OpportunityDeviceModelService opportunityDeviceModelService;

    @Resource
    protected OpportunityEnergyTypeService opportunityEnergyTypeService;

    @Resource
    private XzqhService xzqhService;

    @Resource
    private TProjectService tProjectService;

    @Resource
    protected ProjectCustomerRelationshipService projectCustomerRelationshipService;

    public CommonOpportunityHandle() {
        log.debug("CommonOpportunityHandle instance ....");
    }

    @Override
    public OpportunityClassificationEnum opportunityClassification() {
        return OpportunityClassificationEnum.COMMON;
    }

    @Override
    public Page<OpportunityInfoDto> page(QueryOpportunityPageBO queryOpportunityPageBO) throws Exception {
        log.debug("CommonOpportunityHandle queryPageHandle ....");
        preHandleConditionForPage(queryOpportunityPageBO);

        Page<OpportunityInfoDto> opportunityPage = crmOpportunityService.getOpportunityPage(queryOpportunityPageBO);
        List<OpportunityInfoDto> records = opportunityPage.getRecords();
        if (CollUtil.isEmpty(records)) {
            return opportunityPage;
        }

        postHandlePageData(records, queryOpportunityPageBO);

        return opportunityPage;
    }

    /**
     * Prepares the page conditions for handling opportunities.
     * This method is intended to be called before processing the page to ensure that all necessary data and conditions are met.
     * It specifically processes the area code to fetch related opportunity IDs if the area code is provided.
     * @param bo the business object containing the query parameters, including the area code
     */
    protected void preHandleConditionForPage(QueryOpportunityPageBO bo) {
        log.debug("CommonOpportunityHandle preHandlePageConditions ....");

        // 处理公共条件
        handleCommonConditionForPage(bo);

        // 处理默认条件
        handleDefaultConditionForPage(bo);
    }

    /**
     * Handles the common condition for a page, specifically setting the opportunity ID list based on the area code.
     * @param bo The QueryOpportunityPageBO object containing the area code and to which the opportunity ID list will be set.
     */
    private void handleCommonConditionForPage(QueryOpportunityPageBO bo) {
        if (StrUtil.isNotBlank(bo.getAreaCode())) {
            // 查询商机服务的行政区划子表关联的商机id集合
            bo.setOpportunityIdList(opportunityAreaCodeService.getOpportunityIdListByAreaCode(bo.getAreaCode()));
        }
        if (StrUtil.isNotEmpty(bo.getOpportunityUuid())) {
            bo.setOpportunityIdList(Collections.singletonList(bo.getOpportunityUuid()));
        }
    }

    /**
     * Handles the default condition for a page based on the opportunity classification.
     * This method sets the opportunity classifications in the provided business object
     * depending on whether the current classification is common or not.
     * @param bo the QueryOpportunityPageBO instance to be updated with the appropriate
     *           opportunity classifications
     */
    protected void handleDefaultConditionForPage(QueryOpportunityPageBO bo) {
        log.debug("CommonOpportunityHandle handleOpportunityClassification ....");
        if (OpportunityClassificationEnum.COMMON.equals(opportunityClassification())) {
            log.debug("CommonOpportunityHandle handleOpportunityClassification common ....");
            if (CollUtil.isEmpty(bo.getOpportunityClassifications())) {
                bo.setOpportunityClassifications(Arrays.stream(OpportunityClassificationEnum.values())
                        .map(OpportunityClassificationEnum::getKey)
                        .filter(key -> !key.equals(OpportunityClassificationEnum.COMMON.getKey()))
                        .collect(Collectors.toList()));
            }
            if (ObjectUtil.isNotNull(bo.getOpportunityClassificationEnum()) && !OpportunityClassificationEnum.COMMON.equals(bo.getOpportunityClassificationEnum())) {
                bo.setOpportunityClassifications(Collections.singletonList(opportunityClassification().getKey()));
            }
        } else {
            log.debug("CommonOpportunityHandle handleOpportunityClassification other ....");
            bo.setOpportunityClassifications(Collections.singletonList(opportunityClassification().getKey()));
        }
    }

    /**
     * Processes a list of OpportunityInfoDto objects, enriching each with human-readable names for certain fields.
     * This method converts the enum keys for customer nature, opportunity stage, opportunity type, and opportunity classification
     * into their corresponding value representations and sets these values in the respective DTOs.
     * @param records the list of OpportunityInfoDto objects to be processed
     */
    protected void postHandlePageData(List<OpportunityInfoDto> records,
            QueryOpportunityPageBO queryOpportunityPageBO) throws Exception {
        log.debug("CommonOpportunityHandle postHandlePageData ....");

        commonPostHandlePageData(records);

        defaultPostHandlePageData(records, queryOpportunityPageBO);
    }

    private void commonPostHandlePageData(List<OpportunityInfoDto> records) throws Exception {
        for (OpportunityInfoDto opportunityInfoDto : records) {
            opportunityInfoDto.setCustomerNatureName(CustomerNatureEnum.enumConvertKeyToValue(opportunityInfoDto.getCustomerNature()));
            opportunityInfoDto.setOpportunityStageName(OpportunityStageEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityStage()));
            opportunityInfoDto.setOpportunityTypeName(OpportunityTypeEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityType()));
            opportunityInfoDto.setOpportunityClassificationName(OpportunityClassificationEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityClassification()));

            // 允许的行政区划范围处理
            List<OpportunityAreaCodeDTO> areaCodeDTOS = opportunityAreaCodeService.getAreaCodesByOpportunityUuid(opportunityInfoDto.getUuid());
            opportunityInfoDto.setAllowAreaCodes(CollUtil.isNotEmpty(areaCodeDTOS) ? areaCodeDTOS : Collections.emptyList());
            // 允许的设备型号处理
            List<OpportunityDeviceModel> deviceModels = opportunityDeviceModelService.getDeviceModels(opportunityInfoDto.getUuid());
            opportunityInfoDto.setAllowDeviceModels(CollUtil.isNotEmpty(deviceModels) ? CopyUtils.copyList(deviceModels, OpportunityDeviceModelDTO.class) : Collections.emptyList());
        }
    }

    protected void defaultPostHandlePageData(List<OpportunityInfoDto> records,
            QueryOpportunityPageBO queryOpportunityPageBO) throws Exception {
    }

    /**
     * 查询商机详情
     * @param bo
     * @return
     */
    @Override
    public OpportunityDetailDTO details(GetOpportunityDetailBO bo) throws Exception {
        log.debug("CommonOpportunityHandle detailsHandle ....");
        OpportunityDetailDTO opportunityDetailDTO = new OpportunityDetailDTO();
        opportunityDetailDTO.setOpportunityInfo(getOpportunityBaseInfo(bo));
        opportunityDetailDTO.setClaimList(getOpportunityClaimDtoList(bo.getOpportunityId()));
        opportunityDetailDTO.setQuoteList(getOpportunityQuoteDtoList(bo.getOpportunityId()));
        opportunityDetailDTO.setDesignList(getBimDesignDtoList(bo.getOpportunityId()));
        opportunityDetailDTO.setBimList(getOpportunityBimDtoList(bo.getOpportunityId()));
        opportunityDetailDTO.setPicMap(getOpportunityPicList(bo.getOpportunityId(), Arrays.asList(OpportunityFileTypeEnum._05.getKey(), OpportunityFileTypeEnum._06.getKey(),OpportunityFileTypeEnum._07.getKey())));
        return opportunityDetailDTO;
    }

    private OpportunityInfoDto getOpportunityBaseInfo(GetOpportunityDetailBO bo) throws Exception {
        OpportunityInfoDto opportunityInfoDto = crmOpportunityService.getOpportunityBaseInfo(bo);
        if (ObjectUtil.isNull(opportunityInfoDto)) {
            return opportunityInfoDto;
        }

        postHandleOpportunityBaseInfo(opportunityInfoDto);

        return opportunityInfoDto;
    }


    /**
     * Processes and handles the base information for an opportunity after initial setup.
     * This method ensures that both common and default fields are appropriately managed.
     * @param opportunityInfoDto the data transfer object containing the opportunity's information
     * @throws Exception if an error occurs during the handling of the opportunity's base information
     */
    private void postHandleOpportunityBaseInfo(OpportunityInfoDto opportunityInfoDto) throws Exception {
        try {
            handleCommonFieldsForOpportunityBaseInfo(opportunityInfoDto);

            handleDefaultFieldsForOpportunityBaseInfo(opportunityInfoDto);
        } catch (Exception e) {
            log.error("CommonOpportunityHandle postHandleOpportunityBaseInfo error", e);
        }
    }

    /**
     * Handles the common fields for the opportunity base information.
     * This method processes JSON data, decodes it, and sets up image URLs for both opportunity and clue pictures.
     * It also enriches the DTO with names based on dictionary types.
     * @param opportunityInfoDto the OpportunityInfoDto containing the opportunity information to be processed
     * @throws Exception if an error occurs during the processing of the data
     */
    private void handleCommonFieldsForOpportunityBaseInfo(OpportunityInfoDto opportunityInfoDto) throws Exception {
        log.debug("CommonOpportunityHandle handleCommonFieldsForOpportunityBaseInfo ....");
        // 模版字段处理
        if (StrUtil.isNotEmpty(opportunityInfoDto.getJsonData())) {
            opportunityInfoDto.setJsonData(URLDecoder.decode(opportunityInfoDto.getJsonData(), "UTF-8"));
        }

        //获取商机图片
        if (!StringUtils.isEmpty(opportunityInfoDto.getPicture1())) {
            opportunityInfoDto.setImgReal1(OssUtil.getImgSignURL(opportunityInfoDto.getPicture1(), 1));
            opportunityInfoDto.setImgRealBig1(OssUtil.getImgSignURL(opportunityInfoDto.getPicture1(), 0));
        }
        if (!StringUtils.isEmpty(opportunityInfoDto.getPicture2())) {
            opportunityInfoDto.setImgReal2(OssUtil.getImgSignURL(opportunityInfoDto.getPicture2(), 1));
            opportunityInfoDto.setImgRealBig2(OssUtil.getImgSignURL(opportunityInfoDto.getPicture2(), 0));
        }
        if (!StringUtils.isEmpty(opportunityInfoDto.getPicture3())) {
            opportunityInfoDto.setImgReal3(OssUtil.getImgSignURL(opportunityInfoDto.getPicture3(), 1));
            opportunityInfoDto.setImgRealBig3(OssUtil.getImgSignURL(opportunityInfoDto.getPicture3(), 0));
        }
        //获取线索图片
        if (!StringUtils.isEmpty(opportunityInfoDto.getCluePicture1())) {
            opportunityInfoDto.setClueImgReal1(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture1(), 1));
            opportunityInfoDto.setClueImgRealBig1(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture1(), 0));
        }
        if (!StringUtils.isEmpty(opportunityInfoDto.getCluePicture2())) {
            opportunityInfoDto.setClueImgReal1(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture2(), 1));
            opportunityInfoDto.setClueImgRealBig2(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture2(), 0));
        }
        if (!StringUtils.isEmpty(opportunityInfoDto.getCluePicture3())) {
            opportunityInfoDto.setClueImgReal1(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture3(), 1));
            opportunityInfoDto.setClueImgRealBig3(OssUtil.getImgSignURL(opportunityInfoDto.getCluePicture3(), 0));
        }

        // 行政区划名称处理
        opportunityInfoDto.setXzqhmc(xzqhService.getAreaName(opportunityInfoDto.getXzqhdm()));
        // 商机分类名称处理
        opportunityInfoDto.setOpportunityClassificationName(OpportunityClassificationEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityClassification()));
        // 商机阶段名称处理
        opportunityInfoDto.setOpportunityStageName(OpportunityStageEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityStage()));
        // 商机类型名称处理
        opportunityInfoDto.setOpportunityTypeName(OpportunityTypeEnum.enumConvertKeyToValue(opportunityInfoDto.getOpportunityType()));
        // 申报类别名称处理
        opportunityInfoDto.setCategoryOfDeclarationName(DeclareCategoryEnum.enumConvertKeyToValue(opportunityInfoDto.getCategoryOfDeclaration()));
        // 户籍情况名称处理
        opportunityInfoDto.setHouseholdRegistrationName(HouseholdRegistrationEnum.enumConvertKeyToValue(opportunityInfoDto.getHouseholdRegistration()));

        // 查询是否有施工项目
        TProject project = tProjectService.getProjectByopportunityUuid(opportunityInfoDto.getUuid());
        opportunityInfoDto.setAbleCreateConstructionPorject(ObjectUtil.isNull(project));
    }

    /**
     * Handles the default fields for the opportunity base information.
     * @param opportunityInfoDto the data transfer object containing the opportunity information
     * @throws Exception if an error occurs while handling the default fields
     */
    protected void handleDefaultFieldsForOpportunityBaseInfo(OpportunityInfoDto opportunityInfoDto) throws Exception {
        log.debug("CommonOpportunityHandle handleDefaultFieldsForOpportunityBaseInfo ....");
        // 改造类型名称处理
        opportunityInfoDto.setRenovationTypeName(RenovationType.enumConvertKeyToValue(opportunityInfoDto.getRenovationType()));
    }

    private List<GetLogClaimListDto> getOpportunityClaimDtoList(String opportunityUuid) {
        GetLogClaimListBo logClaimListBo = new GetLogClaimListBo();
        logClaimListBo.setOpportunityId(opportunityUuid);
        logClaimListBo.setClaimType("03");
        return logClaimService.getLogClaimList(logClaimListBo);
    }

    private List<OpportunityQuoteDto> getOpportunityQuoteDtoList(String opportunityUuid) {
        OpportunityQuoteBO opportunityQuoteBo = new OpportunityQuoteBO();
        opportunityQuoteBo.setOpportunityId(opportunityUuid);
        return opportunityQuoteService.getOpportunityQuoteDtoList(opportunityQuoteBo);
    }

    private List<BimDesignDto> getBimDesignDtoList(String opportunityUuid) {
        BimDesignBO bimDesignBo = new BimDesignBO();
        bimDesignBo.setOpportunityId(opportunityUuid);
        return bimDesignService.getBimDesignDtoList(bimDesignBo);
    }

    private List<OpportunityBimDto> getOpportunityBimDtoList(String opportunityUuid) {
        OpportunityBimBO opportunityBimBo = new OpportunityBimBO();
        opportunityBimBo.setOpportunityId(opportunityUuid);
        return opportunityBimService.getOpportunityBimDtoList(opportunityBimBo);
    }

    private Map<String, List<OpportunityFileDto>> getOpportunityPicList(String opportunityUuid, List<String> opportunityFileTypeList) {
        Map<String, List<OpportunityFileDto>> map = new HashMap<>();
        if (StrUtil.isBlank(opportunityUuid) || CollectionUtil.isEmpty(opportunityFileTypeList)) {
            return map;
        }
        // 查询商机文件
        List<OpportunityFileDto> opportunityFileList = opportunityFileService.getOpportunityFileList(opportunityUuid, opportunityFileTypeList);
        // 处理商机文件
        for (OpportunityFileDto opportunityFile : opportunityFileList) {
            // 处理设计图
            if (OpportunityFileTypeEnum._05.getKey().equals(opportunityFile.getFileType())) {
                List<OpportunityFileDto> fileList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(map.get("designDrawings"))) {
                    fileList.addAll(map.get("designDrawings"));
                }
                fileList.add(opportunityFile);
                map.put("designDrawings", fileList);
            }
            // 处理平面图
            if (OpportunityFileTypeEnum._06.getKey().equals(opportunityFile.getFileType())) {
                List<OpportunityFileDto> fileList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(map.get("planeGraphs"))) {
                    fileList.addAll(map.get("planeGraphs"));
                }
                fileList.add(opportunityFile);
                map.put("planeGraphs", fileList);
            }
            // 处理设备告知承诺书
            if (OpportunityFileTypeEnum._07.getKey().equals(opportunityFile.getFileType())) {
                List<OpportunityFileDto> fileList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(map.get("sbgzcns"))) {
                    fileList.addAll(map.get("sbgzcns"));
                }
                fileList.add(opportunityFile);
                map.put("sbgzcns", fileList);
            }

        }
        return map;
    }

    /**
     * 保存处理
     * @param opportunityBO
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Opportunity save(OpportunityBO opportunityBO) throws Exception {
        log.debug("CommonOpportunityHandle saveHandle ....");

        preProcessorBeforeOpportunitySave(opportunityBO);

        Opportunity opportunity = handleOpportunitySave(opportunityBO);
        opportunityBO.setUuid(opportunity.getUuid());

        postProcessorAfterOpportunitySave(opportunity, opportunityBO);

        saveOpportunityAreaCodes(opportunityBO);

        saveOpportunityEnergyTypes(opportunityBO);

        saveOpportunityDeviceModels(opportunityBO);

        saveOpportunityStaff(opportunityBO, opportunity);

        saveOpportunityFile(opportunityBO);

        handleOpportunityLogSave(opportunityBO);

        specialHandle(opportunityBO);

        return opportunity;
    }

    private void preProcessorBeforeOpportunitySave(OpportunityBO opportunityBO) throws Exception {
        validateBusniess(opportunityBO);
    }

    protected void validateBusniess(OpportunityBO opportunityBO) throws Exception {

    }

    @Transactional(rollbackFor = Exception.class)
    public Opportunity handleOpportunitySave(OpportunityBO opportunityBO) throws Exception {
        log.debug("CommonOpportunityHandle handleOpportunitySave ....");
        Opportunity opportunity = crmOpportunityService.getOpportunity(opportunityBO.getUuid());
        convert(opportunityBO, opportunity);
        saveOpportunity(opportunity);
        return opportunity;
    }

    private void postProcessorAfterOpportunitySave(Opportunity opportunity,
            OpportunityBO opportunityBO) throws Exception {
        log.debug("CommonOpportunityHandle postProcessorAfterOpportunitySave ....");
        TProject project = tProjectService.getProjectByopportunityUuid(opportunity.getUuid());
        postProcessorForRelationshipHandle(opportunity, opportunityBO, project);
    }

    protected void postProcessorForRelationshipHandle(Opportunity opportunity, OpportunityBO opportunityBO,
            TProject project) throws Exception {
        log.debug("CommonOpportunityHandle postProcessorForRelationshipHandle ....");

        ProjectCustomerRelationship relationship = projectCustomerRelationshipService.getMainRelationshipByOpportunityUuid(opportunity.getUuid());
        if (ObjectUtil.isNull(relationship)) {
            relationship = new ProjectCustomerRelationship();
            relationship.setMainFlag(ProjectRelationTypeEnum.MAIN.getKey());
            relationship.setDataType(opportunityBO.getProjectRelationDataTypeEnum().getKey());
            relationship.setImportBatch(opportunityBO.getOperateTimeStamp());
            relationship.setDeleted(DeleteEnum._0.getKey());
            relationship.setGmtCreateId(opportunityBO.getOperateUserId());
            relationship.setGmtCreate(opportunityBO.getOperateDate());
        } else {
            relationship.setGmtModified(opportunityBO.getOperateDate());
            relationship.setGmtModifiedId(opportunityBO.getOperateUserId());
        }
        relationship.setProjectUuid(ObjectUtil.isNull(project) ? null : project.getUuid());
        relationship.setMainCustomerId(opportunity.getCustomerId());
        relationship.setMainBusinessId(opportunity.getUuid());
        relationship.setCustomerId(opportunity.getCustomerId());
        relationship.setBusinessId(opportunityBO.getUuid());
        projectCustomerRelationshipService.saveOrUpdate(relationship);
    }

    protected void convert(OpportunityBO opportunityBO, Opportunity opportunity) {
        log.debug("CommonOpportunityHandle convert ....");
        settingCommonFields(opportunityBO, opportunity);
        settingDefaultFields(opportunityBO, opportunity);
    }

    private void settingCommonFields(OpportunityBO opportunityBO, Opportunity opportunity) {
        log.debug("CommonOpportunityHandle settingCommonFields ....");
        if (StrUtil.isEmpty(opportunityBO.getUuid())) {
            opportunity.setUuid(IdUtils.uuid());
            opportunity.setCreateUid(String.valueOf(opportunityBO.getOperateUserId()));
            opportunity.setCreateTime(opportunityBO.getOperateDate());
            opportunity.setDeleted(String.valueOf(DeleteEnum._0.getKey()));
            opportunity.setModifyUid(String.valueOf(opportunityBO.getOperateUserId()));
            opportunity.setModifyTime(opportunityBO.getOperateDate());
            opportunity.setOpportunityOwner(String.valueOf(opportunityBO.getOperateUserId()));
        } else {
            opportunity.setUuid(opportunityBO.getUuid());
            opportunity.setModifyUid(String.valueOf(opportunityBO.getOperateUserId()));
            opportunity.setModifyTime(opportunityBO.getOperateDate());
        }
        opportunity.setJsonData(opportunityBO.getJsonData());
        opportunity.setTemplateId(opportunityBO.getTemplateId());

        opportunity.setEnergyType(ObjectUtil.isNull(opportunityBO.getEnergyType()) ? null : opportunityBO.getEnergyType()
                .getKey());
        opportunity.setXzqhdm(opportunityBO.getAreaCode());
        opportunity.setCompanyId(opportunityBO.getOperateUserCompanyId());
        opportunity.setProjectAddress(opportunityBO.getProjectAddress());
        opportunity.setOpportunityClassification(opportunityBO.getOpportunityClassification().getKey());
        opportunity.setOpportunityStage(opportunityBO.getOpportunityStage().getKey());
        opportunity.setOpportunityName(opportunityBO.getOpportunityName());
        opportunity.setCustomerId(opportunityBO.getCustomerUuid());
        opportunity.setHouseId(opportunityBO.getHouseId());
        opportunity.setOpportunityType(opportunityBO.getOpportunityType().getType());
        opportunity.setJsonData(opportunityBO.getJsonData());
        opportunity.setTemplateId(opportunityBO.getTemplateId());
        opportunity.setLongitude(opportunityBO.getLongitude());
        opportunity.setLatitude(opportunityBO.getLatitude());
        opportunity.setClueId(opportunityBO.getClueId());
        opportunity.setMemo(opportunityBO.getMemo());
        opportunity.setPlanYear(opportunityBO.getPlanYear());

        opportunity.setSex(opportunityBO.getSex());
        opportunity.setPersoninCharge(opportunityBO.getPersonInCharge());
        opportunity.setPersonInChargePhone(opportunityBO.getPersonInChargePhone());

        opportunity.setMobilizationTime(opportunityBO.getMobilizationTime());
        opportunity.setCompleteTime(opportunityBO.getCompleteTime());
        opportunity.setOrderGoodsTime(opportunityBO.getOrderGoodsTime());
        opportunity.setPersoninCharge(opportunityBO.getPersonInCharge());
        opportunity.setCgfType(opportunityBO.getCgfType());
        opportunity.setCgfPhone(opportunityBO.getCgfPhone());
        opportunity.setSjfCompanyName(opportunityBO.getSjfCompanyName());
        opportunity.setSjfPhone(opportunityBO.getSjfPhone());
        opportunity.setCjfCompanyName(opportunityBO.getCjfCompanyName());
        opportunity.setCjfPhone(opportunityBO.getCjfPhone());
        opportunity.setTzfCompanyName(opportunityBO.getTzfCompanyName());
        opportunity.setTzfPhone(opportunityBO.getTzfPhone());
        opportunity.setJlfCompanyName(opportunityBO.getJlfCompanyName());
        opportunity.setJlfPhone(opportunityBO.getJlfPhone());


        // 不确定的参数属性
        opportunity.setAmount(opportunityBO.getAmount());
        opportunity.setBimId(opportunityBO.getBimId());
        opportunity.setWechat(opportunityBO.getWechat());
        opportunity.setEstimatedClosingDate(opportunityBO.getEstimatedClosingDate());
        opportunity.setApplicationType(opportunityBO.getApplicationType());
        opportunity.setDbhhwbh(opportunityBO.getDbhhwbh());
    }

    protected void settingDefaultFields(OpportunityBO opportunityBO, Opportunity opportunity) {
        log.debug("CommonOpportunityHandle settingDefaultFields ....");
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOpportunity(Opportunity opportunity) throws Exception {
        log.debug("CommonOpportunityHandle saveOpportunity ....");
        crmOpportunityService.saveOrUpdate(opportunity);
    }

    protected void saveOpportunityFile(OpportunityBO opportunityBO) {
        if (opportunityBO.addOpportunity() && (CollUtil.isNotEmpty(opportunityBO.getDesignDrawings()) || CollUtil.isNotEmpty(opportunityBO.getPlaneGraphs())|| CollUtil.isNotEmpty(opportunityBO.getSbgzcns()))) {
            log.debug("CommonOpportunityHandle saveOpportunityFile ....");
            opportunityFileService.saveOpportunityFile(opportunityBO.convertToOpportunityFileBO());
        }
    }

    protected void saveOpportunityStaff(OpportunityBO opportunityBO, Opportunity opportunity) throws Exception {
        if (opportunityBO.addOpportunity() && StrUtil.isNotEmpty(opportunityBO.getPersonInCharge())) {
            log.debug("CommonOpportunityHandle saveOpportunityStaff ....");
            OpportunityStaffBO staffBO = opportunityBO.convertToOpportunityStaffBO();
            staffBO.setOpportunityUuid(opportunity.getUuid());
            opportunityStaffService.saveStaff(staffBO);
        }
    }

    protected void saveOpportunityAreaCodes(OpportunityBO opportunityBO) throws Exception {
        if (CollUtil.isNotEmpty(opportunityBO.getAllowAreaCodes())) {
            log.debug("CommonOpportunityHandle saveOpportunityAreaCodes ....");
            opportunityAreaCodeService.save(opportunityBO.convertToOpportunityAreaCodeBo());
        }
    }

    protected void saveOpportunityEnergyTypes(OpportunityBO opportunityBO) throws Exception {
        if (CollUtil.isNotEmpty(opportunityBO.getEnergyTypes())) {
            log.debug("CommonOpportunityHandle saveOpportunityEnergyTypes ....");
            opportunityEnergyTypeService.save(opportunityBO.convertToOpportunityEnergyTypeBo());
        }
    }

    protected void saveOpportunityDeviceModels(OpportunityBO opportunityBO) throws Exception {
        log.debug("CommonOpportunityHandle saveOpportunityDeviceModels ....");
        opportunityDeviceModelService.saveBatch(opportunityBO.convertToOpportunityDeviceModelBo());
    }

    protected void handleOpportunityLogSave(OpportunityBO opportunityBO) {
        log.debug("CommonOpportunityHandle handleOpportunityLogSave ....");
        logOperateService.saveLogOperate(logOperateService.buildLogOperate(opportunityBO));
    }

    protected void specialHandle(OpportunityBO opportunityBO) throws Exception {
        log.debug("CommonOpportunityHandle specialHandle ....");

        if (opportunityBO.addOpportunity() && StrUtil.isNotEmpty(opportunityBO.getClueId())) {
            SaveUpdateClueVo saveUpdateClueVo = new SaveUpdateClueVo();
            saveUpdateClueVo.setUuid(opportunityBO.getClueId());
            saveUpdateClueVo.setClueStage(ClueStageEnum.TO_OPPORTUNIY.getKey());
            saveUpdateClueVo.setUserInfo(opportunityBO.getUserInfo());
            crmClueService.saveUpdateClue(saveUpdateClueVo);
        }
    }

}
